<?php
/**
 * @package common
 */
require_once '_constants.php';
require_once '_sitecontext.php';

/**
 * One instance of this class stands for one picture.
 * This class provides additional functionality which operates
 * with the picture.
 */
class Img {
	/** @var resource - instance of the image resource */
	private $image;
	/** @var string - full filename which stands for this image on a filesystem */
	private $filename;
	/** images private helper data */
	private $info;

	/**
	 * Create new Img.
	 * Provide $filename or $resource.
	 *
	 * @param string $filename - full filename which stands for this image on a filesystem
	 * @param resource $resource - instance of the image resource
	 */
	function __construct(string $filename = null, resource $resource = null) {
		$this->filename = $filename;
		$this->info = getimagesize($filename);
		if ($this->info == false)
			throw new Exception("Cannot access picture '$filename'");

		if (!is_resource($resource))
			switch ($this->info[2]) {
				case IMAGETYPE_GIF:
					$this->image = imagecreatefromgif($filename);
					break;
				case IMAGETYPE_JPEG2000:
				case IMAGETYPE_JPEG:
					$this->image = imagecreatefromjpeg($filename);
					break;
				case IMAGETYPE_PNG:
					$this->image = imagecreatefrompng($filename);
					break;
				default:
					throw new Exception("Bad image extension");
			}
		else
			$this->image = $resource;
	}
	
	/**
	 * Width of the image.
	 *
	 * @return int
	 */
	function getWidth() {
		return $this->info[0];
	}
	/**
	 * Height of the image.
	 *
	 * @return int
	 */
	function getHeight() {
		return $this->info[1];
	}
	
	/**
	 * Filename of this image
	 *
	 * @return string - filename
	 */
	function getFileName() {
		return $this->filename;
	}
	
	/**
	 * Proportionaly resize image.
	 *
	 * @param float $ratio
	 * 
	 * @return Img
	 */
	function resizeProportional($ratio, string $newFilename = null) {
		return $this->resize($this->getWidth() * $ratio, $this->getHeight() * $ratio, $newFilename);
	}
	
	const NEWFILENAME_PREFIX = "new_";
	/**
	 * Resize Image, save it in the same location as original image was with altered name (added prefix new_).
	 * If proportional is on, width is used as first otherwise (in case width == 0) is used height.
	 *
	 * @param int $width
	 * @param int $height
	 * @param string $newFilename - file name of the new image. 
	 * 		If not provided, new image is created with prefix Img::NEWFILENAME_PREFIX
	 * @param boold $enlarge - wheter to enlarge picture if needed or not
	 *
	 * @return Img
	 */
	function resize($width = 0, $height = 0, string $newFilename = null, $enlarge = false) {
		if ( $height < 0 || $width < 0  || $width == 0 && $height == 0) {
			throw new Exception("Bad new image size: height = '$height''; width = '$width'");
		}
		if ($height == 0 || $width == 0)
			$proportional = true;
		else 
			$proportional = false;

		$widthOrig = $this->info[0];
		$heightOrig = $this->info[1];

		/*
		 * Deal with a proportion if set.
		 */
		if ($proportional) {
			$proportion = $widthOrig / $heightOrig;

			if ($width != 0) {
				$widthFinal = $width;
				$heightFinal = $widthFinal / $proportion;
			} else {
				$heightFinal = $height;
				$widthFinal = $heightFinal * $proportion;
			}
		} else {
			$widthFinal = $width;
			$heightFinal = $height;
		}
		
		/** if filename wasn't specified, generate one */
		if (is_null($newFilename)) {
			$oldFilename = basename($this->filename);
			$imgDir = SiteContext::getSiteContext()->getSiteInf()->getPathFilesystemImg();
			$newFilename = $imgDir . Constants::FS_DIRDELIMITER . self::NEWFILENAME_PREFIX . $oldFilename;
		}
		
		/* Do not enlarge */
		if (!$enlarge) {
			if ($widthFinal >= $widthOrig || $heightFinal >= $heightOrig) {
				$this->copyImage($this->image, $newFilename);
				return new Img($newFilename);
			}
		}

		/*
		 * Create the new image, and scale the original into it.
		 */
		$image = imagecreatetruecolor($widthFinal, $heightFinal);

		imagecolortransparent($image, imagecolorallocate($image, 0, 0, 0));
		imagealphablending($image, false);
		imagesavealpha($image, true);

		imagecopyresampled($image, $this->image, 0, 0, 0, 0, $widthFinal, $heightFinal, $widthOrig, $heightOrig);

		$this->copyImage($image, $newFilename);

		return new Img($newFilename, $image);
	}
	
	/**
	 * Copy resource $image to $newFilename - respectively save it.
	 * 
	 * @param resource $image
	 * @param string $newFilename
	 */
	private function copyImage(resource $image, string $newFilename) {
		switch ($this->info[2]) {
			case IMAGETYPE_GIF:
				imagegif($image, $newFilename);
				break;
			case IMAGETYPE_JPEG2000:
			case IMAGETYPE_JPEG:
				imagejpeg($image, $newFilename);
				break;
			case IMAGETYPE_PNG:
				imagepng($image, $newFilename);
				break;
			default:
				throw new Exception("Bad image descriptor: ".$this->info[2]);
		}
	}
	
	/** default watermark filename */
	const DEFAULT_WATERMARK = Constants::IMG_WATERMARK;
	
	/**
	 * Add watermark to the image.
	 * 
	 * @param Img $watermark - optional user specified watermark
	 */
	public function addWatermark(Img $watermark = null) {
		if ($watermark == null) {
			$watermark = SiteContext::getSiteContext()->getSiteInf()->getPathFilesystemImg() . Constants::FS_DIRDELIMITER . self::DEFAULT_WATERMARK;
			$watermark = new Img($watermark);
		}
		
		//$watermark = $watermark->resize($this->getWidth());
		
		$dest_x = $this->getWidth() - $watermark->getWidth() - 5;  
		$dest_y = $this->getHeight() - $watermark->getHeight() - 5;  
		imagecopy($this->image, $watermark->image, 0, 0, 0, 0, $watermark->getWidth(), $watermark->getHeight());
		$this->copyImage($this->image, $this->filename);
		imagedestroy($watermark->image);
	}
}
?>